﻿#ifndef SQLOPERATOR_H
#define SQLOPERATOR_H

#include <QSqlDatabase>
#include <QSqlQuery>
#include <QHash>
#include <QString>
#include <QVariant>

/**
 * @brief Sqlite数据库基本操作类
 *
 */
class SqliteManager
{
public:
    /**
     * @brief 判断数据库表是否存在
     * @param tableName: 数据库表名
     * @return
     */
    bool isExistTable(const QString &tableName);

    /**
     * @brief 创建数据库表
     * @param tableName: 数据库表名
     * @param fields: 字段(字段名和类型，如{"name", "varchar(5)"})
     * @param pks: 主键
     * @return
     */
    bool createTable(const QString &tableName,
                     const QHash<QString, QString> &fields,
                     const QList<QString> &pks);

    /**
     * @brief 查询数据(适用于单表选择)
     * @param tableName: 数据表名
     * @param fields: 选择字段
     * @param data: 查询到的数据(按fields的顺序)
     * @return
     */
    bool selectData(const QString &tableName,
                    const QList<QString> &fields,
                    QList<QVariantList> &data);

    /**
     * @brief 查询数据(适用于单表选择)
     * @param tableName: 数据表名
     * @param fields: 选择字段
     * @param whereConditions: where条件
     * @param data: 查询到的数据(按fields的顺序)
     * @return
     */
    bool selectData(const QString &tableName,
                    const QList<QString> &fields,
                    const QHash<QString, QVariant> &whereConditions,
                    QList<QVariantList> &data);

    /**
     * @brief 查询数据(通过sql查询, 多表联合查询)
     * @param sql: select语句
     * @param fields: 选择字段
     * @param data: 查询到的数据(按fields的顺序)
     * @return
     */
    bool selectDataBySql(const QString &sql,
                         const QList<QString> &fields,
                         QList<QVariantList> &data);

    /**
     * @brief 插入行数据
     * @param tableName: 数据表名
     * @param fields: 插入字段
     * @param data: 插入数据(数据与字段的顺序需一致)
     * @return
     */
    bool insertRowData(const QString &tableName,
                       const QList<QString> &fields,
                       const QVariantList &data);

    /**
     * @brief 插入行数据，在事务中执行
     * @param tableName: 数据表名
     * @param fields: 插入字段
     * @param data: 插入数据(数据与字段的顺序需一致)
     * @return
     */
    bool insertRowDataInTransaction(const QString &tableName,
                                    const QList<QString> &fields,
                                    const QVariantList &data);


    /**
     * @brief 插入多行数据
     * @param tableName: 数据表名
     * @param fields: 字段
     * @param data: 插入数据(数据与字段的顺序需一致)
     * @return
     */
    bool insertRowsData(const QString &tableName,
                        const QList<QString> &fields,
                        const QList<QVariantList> &data);

    /**
     * @brief 更新数据
     * @param tableName: 数据表名
     * @param data: 更新的字段数据(字段名和值，如{"age", 27})
     * @param whereConditions: where条件(字段名和值，如{"age", 27})
     * @return
     */
    bool updateData(const QString &tableName,
                    const QHash<QString, QVariant> &data,
                    const QHash<QString, QVariant> &whereConditions);

    /**
     * @brief 删除数据
     * @param tableName: 数据表名
     * @param whereConditions: where条件(字段名和值，如{"age", 27})
     * @return
     */
    bool deleteData(const QString &tableName,
                    const QHash<QString, QVariant> &whereConditions);

    /**
     * @brief 执行sql语句
     * @param sql: sql语句
     * @return 执行结果
     */
    bool exec(const QString &sql);

    /**
     * @brief 是否支持事务
     * @return
     */
    bool hasTransactions();

    /**
     * @brief 开启事务
     * @return
     */
    bool transactionStart();

    /**
     * @brief 结束事务
     * @return
     */
    bool transactionEnd();

    /**
     * @brief 事务提交
     * @return
     */
    bool commit();

    /**
     * @brief 事务回滚
     * @return
     */
    bool rollback();

    /**
     * @brief 记录数量(在执行select语句后，可用该函数获取select的大小)
     * @return
     */
    int size();

    /**
     * @brief 获取数据表字段
     * @param tableName: 数据表名
     * @param fieldsName: [OUT]字段
     * @return
     */
    bool getTableFieldsInfo(const QString &tableName,
                            QList<QString> &fieldsName);

    /**
     * @brief 获取最新一次执行的sql语句
     * @return
     */
    QString lastQuerySql();

    /**
     * @brief 获取最新的错误信息
     * @return 错误信息
     */
    QString lastError() const;

private:
    /**
     * @brief 校验数据表信息(数据表和字段是否存在)
     * @param tableName: 数据表名
     * @param fields: 字段
     * @return
     */
    bool checkTableInfo(const QString &tableName,
                        const QList<QString> &fields);

protected:
    QSqlDatabase  m_db;
    QString       m_connectName;
    QSqlQuery     m_query;
    QString       m_lastError;
};

#endif // SQLOPERATOR_H

